package zbl.c0.parser;

import java.io.IOException;

import zbl.c0.error.Errors;
import zbl.c0.error.Perror;
import zbl.c0.inter.CodeStack;
import zbl.c0.inter.GlobalStack;
import zbl.c0.inter.Interpret;
import zbl.c0.inter.StringStack;
import zbl.c0.lexer.Lexer;
import zbl.c0.lexer.Num;
import zbl.c0.lexer.Tag;
import zbl.c0.lexer.Token;
import zbl.c0.symbol.FuncTable;
import zbl.c0.symbol.Symbol;
import zbl.c0.symbol.SymbolTable;

/**
 * 		语法分析器
 * 
 * @author 朱伯龙
 *
 */

public class Parser {

	private Lexer lexer;			// 语法分析器包含的词法分析器
	private Token curToken;			// 保存当前词法分析器返回的Token词法单元
	
	//    语法分析中的跳跃分析标记，构造语法分析器时全部初始化为False
	//在分析中由需要继续超前读取信息的分析方法置其为True,在需要跳过的
	//分析中，每忽略一次就要还原这些标记为False.
	
	//来源：Program();  使用： VarExplanation() , FuncDefine()
	private Boolean skip_DeclHead;
	//		是否含有main函数标记
	private Boolean hasMain;
	
	
	//____________________符号表相关___________________
	private SymbolTable symboltable;		//  符号表
	private FuncTable curFuncTable;			//  当前函数表， 便于向符号表中添加函数表
	
	
	//___________________运行时环境相关_________________
	private GlobalStack globalstack;
	private CodeStack codestack;
	private StringStack strstack;
	
	private Interpret interpret;
									
									// 语法分析器构造函数，加载指定的词法分析器
	public Parser(Lexer lexer) throws IOException 
	{ 
		//  ##################  初始化标记       #####################
		skip_DeclHead = false;
		hasMain = false;
		
		//  ##################  初始化符号表信息       ###################
		symboltable = new SymbolTable();
		curFuncTable = null;		//  如果curFuncTable == null 则说明还未定义任何函数，此时的
									//	所有常量声明，变量声明都应该加入到全局符号表中。
									//  如果curFuncTable != null 则应该加入到curFuncTable对应的
									//  符号表中。
		
		
		//  ##################  初始化运行时环境信息      ###################
		globalstack = new GlobalStack(500);
		
		codestack = new CodeStack();
		strstack = new StringStack();
		
		
		
		//  ##################  加载词法分析器，开始运行    ###################
		this.lexer = lexer; 
		System.out.println("语法分析器开始工作...........");
		move(); 
	}
	
	/**
	 * 	    语法分析器前移方法，调用词法分析器的scan()方法，
	 * 读入下一个Token到curToken中.
	 */
	private void move()throws IOException{
		curToken = lexer.scan();
	}
	
	/**
	 *		检测当前读取的词法单元的tag值是否与期望的相匹配	    
	 * 
	 * @param expectedTag 期望的词法单元tag值
	 */
	private void match(int expectedTag) throws IOException{
		
		if(curToken.tag == expectedTag){ 
			move();
			if(curToken == null)
			{
				//System.out.println("读取到非法字符，语法分析程序终止！！！");
				//System.exit(-1);
				curToken = new Token(-2);   //  -2不会与任何一个标记重复
			}
		}
		else{
			new Perror(Errors.GraUnmatched).printErrorInfo(lexer.getLineno(), lexer.getWordno());
			switch(expectedTag){
			case '+':
			case '-':
			case '{':
			case '}':		
			case '(':
			case '=':
			case ')':
			case '*':
			case '/':
			case ';':
			case ',':		System.out.println("当前是  "+curToken.tag+"  缺少符号      "+(char)expectedTag); 
							break;
			case Tag.EQUAL:	System.out.println("当前是  "+curToken.tag+"  缺少符号     == "); 
							break;
			case Tag.SMALLER_EQUAL:	System.out.println("当前是  "+curToken.tag+"  缺少符号     <= "); 
									break;
			case Tag.LARGER_EQUAL:	System.out.println("当前是  "+curToken.tag+"  缺少符号     >= "); 
									break;
			case Tag.NOT_EQUAL:	System.out.println("当前是  "+curToken.tag+"  缺少符号     != "); 
								break;
			}
			if(curToken.tag == -1){
				System.out.println("报错中读到文件结束符号，程序终止");
				System.exit(-1);
			}
			//match(curToken.tag);
			//System.exit(-1);
		}
	}
	
	/**
	 * 		在相关的符号表中查找对应的符号是否已经声明
	 * @param idstr
	 */
	public int checkId(String idstr){
		if(curFuncTable.getArgs(idstr) != null)
			return 1;							//  表示在当前函数表的参数表中定义
		if(curFuncTable.getSym(idstr) != null)
			return 2;							//  表示在当前函数表的符号表中定义
		if(symboltable.getFunc(idstr) != null)
			return 3;							//	表示在函数表中定义，即已定义的函数名
		if(symboltable.getGlobal(idstr) != null)
			return 4;							//  表示在全局符号表中定义
		
		return 0;								//	表示该标志符未定义
	}
	
	/**
	 * 		从符号表中查找指定名称的符号
	 * @param str
	 * @return
	 */
	public Symbol getSym(String str){
		switch(checkId(str)){
		case 1:		return (Symbol) curFuncTable.getArgs(str);
		case 2:		return (Symbol) curFuncTable.getSym(str);
		case 4:		return (Symbol) symboltable.getGlobal(str);
		default:	return null;
		}
	}
	
	/**
	 * 		根据函数名称返回函数信息表
	 * @param funcname
	 * @return
	 */
	public FuncTable getFunc(String funcname){
		return (FuncTable) symboltable.getFunc(funcname);
	}
	
	/**
	 * 
	 * <Program>  ::=  [<ConstExplanation>] [<VarExplanation>] { <FuncDefine> } <MainFunc>
	 * 
	 * FIRST(<ConstExplanation>) = { CONST }
	 * FIRST(<VarExplanation>) = { INT }
	 * FIRST(<FuncDefine>) = { INT , VOID }
	 * FIRST(<MainFunc>) = { VOID }
	 * FOLLOW(<ConstExplanation>) = { INT }
	 * 
	 * FIRST(<Program>) = { CONST , INT , VOID }
	 * FOLLOW(<Program>) = { '-1' }
	 * 
	 *     由于当读到'int'时无法区分到底是<VarExplanation>还是<FuncDefine>中的<DeclHead>
	 * 部分，所以要向下继续探测，因此设置skip_DeclHead作为跳过<DeclHead>分析部分的标记，好让
	 * <VarExplanantion>的分析保持一致。当读到“void”时<FuncDefine>与<MainFunc>冲突
	 * 	   // 由于Mainfunc 以及 FuncDefine 仅仅在 Program 的右侧出现，可以简化一些判断
	 * 
	 *     看下面的分析过程可以知道FuncDefine中的"void" 关键字一定会在调用<FunDefine>前
	 * 被消耗掉。所以在处理<FuncDefine>中的"void"分支时，应该跳过"void"关键字
	 * 
	 * @throws IOException
	 **/
	public void Program() throws IOException{
		
		System.out.println();
		System.out.println();
		if(curToken.tag == Tag.CONST){
			ConstExplanation();
		}
		
		if(curToken.tag == Tag.INT){
			
			String str = new String("");
			str = DeclHead();				//  替<VarExplanation> 或者 <FuncDefine> 超前分析<DeclHead>
			skip_DeclHead = true;

			switch(curToken.tag){
			case ',':
			case ';': VarExplanation(str); break;
			case '(': FuncDefine(str); break;
			
			default:  	System.out.println("Error Occured When Analyzing <Program>01, we resume and continue");
						new Perror(Errors.GraGloFuncDefine).printErrorInfo(lexer.getLineno(), lexer.getWordno());
						//System.exit(-1);
						skipToVoidInt();
						skip_DeclHead = false;
						break;
			}
		}
		
		while(curToken.tag == Tag.INT || curToken.tag == Tag.VOID){
								// 连续的函数定义, 如果探测到是Main函数的定义，则跳出循环
			if(curToken.tag == Tag.INT)
			{
				FuncDefine(null);		// 读到 "int" 说明一定是函数定义
				continue;
			}else{					// 读到 "void" 进一步判断
				match(Tag.VOID);	// 提前替<FuncDefine>或者<MainFunc>匹配了一个"void"关键字
				if(curToken.tag == Tag.ID){		// 说明是函数定义
												// <FuncDefine>中的VOID一定会被消耗掉
					FuncDefine(null);
					continue;
				}
				if(curToken.tag == Tag.MAIN){	// 说明是Main函数的定义
												// 由于主函数只在<Program>的右侧出现，而且一定会被提前匹配掉"void"
												// 关键字，所以不为主函数设置其忽略关键字了，且直接从"main"开始分析
					MainFunc();
					break;
				}
												// 正常不可能执行到这里，出错的地方！！！！
				System.out.println("Error Occured When Analyzing <Program>02语法分析程序终止！！！");
				new Perror(Errors.GraMainFuncDefine).printErrorInfo(lexer.getLineno(), lexer.getWordno());
				System.exit(-1);
				break;
			}
		}
		if(hasMain == false)
		{
			System.out.println("*****"+ curToken.tag);
			new Perror(Errors.SynNoneMain).printErrorInfo(lexer.getLineno(), lexer.getWordno());
			System.exit(-1);
		}
		
		if(curToken.tag != -1)					// 未读取到，源程序终结符号  -1
		{
			new Perror(Errors.GraUnexpectedEnd).printErrorInfo(lexer.getLineno(), lexer.getWordno());
			System.exit(-1);
		}
		System.out.println("语法分析完毕！！！");
		
		System.out.println("现在开始解释执行.......");
		System.out.println();
		System.out.println();
										//  初始化解释执行器,并为其加载必要的运行信息
		
		if(Perror.hasError()==false){	//  如果没有错误
			interpret = new Interpret(globalstack, codestack, symboltable, strstack);
		
								//	开始解释执行
			interpret.showCode();
			interpret.execute();
		}else{
			System.out.println("源程序含有错误，跳过解释执行的部分！！！");
		}
		
		return;
	}
	
	/**
	 * <ConstExplanation>  ::=  const  <ConstDefine> { , <ConstDefine>} ;
	 * 
	 * FIRST(<ConstExplanation>) = { CONST }
	 * FOLLOW(<ConstExplanation>) = { INT , IF, DO, ID, RETURN, SCANF, PRINTF , '{' , ';' }
	 * 
	 * @throws IOException
	 */
	private void ConstExplanation() throws IOException{
		
		match(Tag.CONST);
		
		ConstDefine();
		
		while(curToken.tag == ','){
			match(',');
			ConstDefine();
		}
		
		match(';');
		
		return;
	}
	
	/**
	 * <ConstDefine>   ::=   <Id> = <Number>
	 * 
	 * FIRST(<ConstDefine>) = { ID }
	 * FOLLOW(<ConstDefine>) = { ',' , ';' }
	 * 
	 * @throws IOException
	 */
	private void ConstDefine() throws IOException{
		int var;
		String name = new String("");
		name = curToken.toString();
		
		match(Tag.ID);
		if(curToken.tag != '=')
		{
			new Perror(Errors.SynConstNoneInit).printErrorInfo(lexer.getLineno(), lexer.getWordno());
			skipConstDefine();
			return;
			//System.exit(-1);
		}
		match('=');
		var = Number();
		
		
		if(curFuncTable == null)				//  表示该常量是全局常量
		{			
			if(symboltable.addSym(name, Symbol.CONST, var)==false){				//  填写全局符号表信息
				new Perror(Errors.SynIdConflict).printErrorInfo(lexer.getLineno(), lexer.getWordno());
				//System.exit(-1);
			}
		}else{
			if(curFuncTable.reserve(name, Symbol.CONST, var)==false){
				new Perror(Errors.SynIdConflict).printErrorInfo(lexer.getLineno(), lexer.getWordno());
				//System.exit(-1);
			}
		}
		
		return;
	}
	
	/**
	 * <Number>   ::=   [ + | - ]  <NZDigit>  { <Digit> } 
	 * 					| ０
	 * FISRT(<Number>) = { '+' , '-' , NUM }
	 * FOLLOW(<Number>) = { '*' , '/' , '+' , '-' , '<' , <= , '>' , >= , != , == , ')' , ',' , ‘;’ , '}' , ')' }
	 * 
	 * @throws IOException
	 */
	private int Number() throws IOException{
		Num num;
		
		switch(curToken.tag){
		case '+':		match(curToken.tag);
						num = (Num)curToken;
						match(Tag.NUM);
						return (num.value);
						
		case '-':		match(curToken.tag);
						num = (Num)curToken;
						match(Tag.NUM);
						return (-num.value);
						
		case Tag.NUM:	num = (Num)curToken;
						match(Tag.NUM); 
						return (num.value);
		
		default:		System.out.println("Error Occured When Analyzing <Number>语法分析程序终止！！！");
						new Perror(Errors.GraNeedNum).printErrorInfo(lexer.getLineno(), lexer.getWordno());
						System.exit(-1);
		}
		return Integer.MIN_VALUE;
	}
	
	/**
	 * <VarExplanation>   ::=   <DeclHead>  { , <Id> } ;
	 * 
	 * FIRST(<DeclHead>) = { INT }
	 * FOLLOW(<DeclHead>) = { ',' , ';' , '('}
	 * 
	 * FIRST(<VarExplanation>) = FIRST(<DeclHead>) = { INT }
	 * FOLLOW(<VarExplanation>) = { INT , VOID , IF, DO, ID, RETURN, SCANF, PRINTF , '{' , ';' }
	 * 
	 * @throws IOException
	 */
	private void VarExplanation(String str) throws IOException{
		String name = new String("");
		int addr;
		if(skip_DeclHead == false){
			name = DeclHead();
		}else{									// 表示<DeclHead>部分已经被Program提前分析
			skip_DeclHead = false;				// 参数str保存已被提前分析的参数名称
			name = str;
		}
		
		if(curFuncTable==null)
		{
			addr = globalstack.getAddr();
			
			if(symboltable.addSym(name, Symbol.VAR, addr)){
				globalstack.push();
			}else{
				new Perror(Errors.SynIdConflict).printErrorInfo(lexer.getLineno(), lexer.getWordno());
				//System.exit(-1);
			}
		}else{
			if(curFuncTable.reserve(name, Symbol.VAR, -1)==false){
				new Perror(Errors.SynIdConflict).printErrorInfo(lexer.getLineno(), lexer.getWordno());
				//System.exit(-1);
			}
		}
		
		while(curToken.tag == ','){
			match(',');
			name = curToken.toString();
			match(Tag.ID);
			
			if(curFuncTable==null)
			{
				addr = globalstack.getAddr();
				
				if(symboltable.addSym(name, Symbol.VAR, addr)){
					globalstack.push();
				}else{
					new Perror(Errors.SynIdConflict).printErrorInfo(lexer.getLineno(), lexer.getWordno());
					//System.exit(-1);
				}
			}else{
				if(curFuncTable.reserve(name, Symbol.VAR, -1)==false){
					new Perror(Errors.SynIdConflict).printErrorInfo(lexer.getLineno(), lexer.getWordno());
					//System.exit(-1);
				}
			}
		}
		if(curToken.tag == '='){
			new Perror(Errors.SynVarInit).printErrorInfo(lexer.getLineno(), lexer.getWordno());
			skipVarExplanation();
		}
		
		match(';');
			
		return;
	}
	
	/**
	 * <DeclHead>   ::=   int  <Id>
	 * 
	 * FIRST(<DeclHead>) = { INT }
	 * FOLLOW(<DeclHead>) = { ',' , ';' , '('}
	 * 			返回<Id>对应的串信息
	 * @throws IOException
	 */
	private String DeclHead() throws IOException{
		
		String str = new String("");
		match(Tag.INT);
		str = curToken.toString();
		match(Tag.ID);
		
		return str;
	}
	
	/**
	 * <FuncDefine>   ::=  ( <DeclHead>  |  void  <Id>  ) <Argument> <ComStmt>
	 * 
	 * FIRST(<DeclHead>) = { INT }
	 * FISRT(<Argument>) = { '(' }
	 * FOLLOW(<DeclHead>) = { ',' , ';' , '('}
	 * 
	 * FIRST(<FuncDefine>) = { INT , VOID }
	 * FOLLOW(<FuncDefine>) = { VOID }
	 * 
	 * @throws IOException
	 */
	private void FuncDefine(String str) throws IOException{
		String funcname = new String("");
		int retType = FuncTable.VOID;
		
		if(skip_DeclHead == true)			// 表示<DeclHead>部分已经被Program提前分析
		{									// 参数str保存已被提前分析的参数名称
			skip_DeclHead = false;
			funcname = str;					//  此处的函数返回类型应该为int
			retType = FuncTable.INT;
		}else{
			if(curToken.tag == Tag.INT){	// 表示<DeclHead>部分需要自己分析
				funcname = DeclHead();		//  此处的函数返回类型应该为int
				retType = FuncTable.INT;
			}else if(curToken.tag == Tag.ID){	//  此处的函数返回类型应该为void
				funcname = curToken.toString();
				retType = FuncTable.VOID;
				match(Tag.ID);				
			}else {
											// 报错！！！   正常不可能执行到这的代码
				System.out.println("Error Occured When Analyzing <FuncDefine>语法分析程序终止！！！");
				new Perror(Errors.GraMainFuncDefine).printErrorInfo(lexer.getLineno(), lexer.getWordno());
				//System.exit(-1);
			}
		}	
		
		curFuncTable = new FuncTable(funcname, retType);	//  添加函数符号表
		if(symboltable.addFunc(curFuncTable)==false){
			new Perror(Errors.SynFuncAgain).printErrorInfo(lexer.getLineno(), lexer.getWordno());
			skipTo('}');
			match('}');
			return;
		}
		curFuncTable.addr = codestack.getTop();	//  添加函数的入口地址
		
		
		Argument();
		ComStmt();
		
		if(curFuncTable.retType == FuncTable.VOID)			//  void返回类型的函数    不能有2型return
			if(curFuncTable.hasRet == 2)
			{
				System.out.println("函数  "+funcname+"  :");
				new Perror(Errors.SynVoidRetError).printErrorInfo(lexer.getLineno(), lexer.getWordno());
				//System.exit(-1);
			}
		if(curFuncTable.retType == FuncTable.INT)			//  int返回类型的函数   必须且只能有2型return
			if(curFuncTable.hasRet != 2)
			{
				System.out.println("函数  "+funcname+"  :");
				new Perror(Errors.SynIntRetError).printErrorInfo(lexer.getLineno(), lexer.getWordno());
				//System.exit(-1);
			}
		
		if(curFuncTable.hasRet == 0)					//  没有出现过return语句    则需在此添加RET指令
			codestack.genRET(0);						//	添加函数的返回指令，0表示子函数返回
		return;		
	
	}
	
	/**
	 * <Argument>   ::=  ‘(’ <ArgTable> ‘)’
	 * 
	 * FISRT(<Argument>) = { '(' }
	 * FOLLOW(<Argument>) = { '{' }
	 * 
	 * @throws IOException
	 */
	private void Argument() throws IOException{
		
		match('(');
		ArgTable();
		match(')');
		
		return;
	}
	
	/**
	 * <ArgTable>   ::=   int  <Id> { , int <Id> }  
	 * 					| <Blank>
	 * 
	 * FOLLOW(<ArgTable>) = {  }
	 * 
	 * FIRST(<ArgTable>) = { INT , E }
	 * FOLLOW(<ArgTable>) = { ')' }
	 * 
	 * @throws IOException
	 */
	private void ArgTable() throws IOException{
		String argname = new String("");
		if(curToken.tag == Tag.INT){
			match(Tag.INT);
			argname = curToken.toString();
			match(Tag.ID);
			if(curFuncTable.addArgs(argname)==false){
				new Perror(Errors.SynIdConflict).printErrorInfo(lexer.getLineno(), lexer.getWordno());
				System.exit(-1);
			}
			
			while(curToken.tag == ','){
				match(',');
				match(Tag.INT);
				argname = curToken.toString();
				match(Tag.ID);
				if(curFuncTable.addArgs(argname)==false){
					new Perror(Errors.SynIdConflict).printErrorInfo(lexer.getLineno(), lexer.getWordno());
					System.exit(-1);
				}
			}
		}
		if(!argname.equals(""))
			curFuncTable.hasArgs = true;
		else
			curFuncTable.hasArgs = false;
		
		return;
	}
	
	/**
	 * <MainFunc>  ::=  void main ‘(’ ‘)’ <ComStmt>
	 * 
	 * FOLLOW(<ComStmt>) > FOLLOW(<MainFunc>)
	 *
	 * FIRST(<MAinFunc>) = { VOID }
	 * FOLLOW(<MainFunc>) = { '-1' }
	 * 
	 * @throws IOException
	 */
	private void MainFunc() throws IOException{
						//  这里不匹配"void" ， 具体参见Program()中调用MainFunc()中的注释
		match(Tag.MAIN);
		
		hasMain = true;
		curFuncTable = new FuncTable("main", FuncTable.VOID);	//  添加Main函数符号表
		symboltable.addFunc(curFuncTable);
		curFuncTable.hasArgs = false;
		
		curFuncTable.addr = codestack.getTop();					//  添加main函数的入口地址

		codestack.reverWrt(curFuncTable.addr);
		
		
		match('(');
		match(')');
		ComStmt();

		codestack.genRET(1);					//	添加函数的返回指令，1表示main函数返回
		return;
	}
	
	/**
	 * 
	 * <ComStmt>   ::=  ‘{’ [ <ConstExplanation> ] [ <VarExplanation> ] <StmtSeq> ‘}’
	 * 
	 * FIRST(<ConstExplanation>) = { CONST }
	 * FIRST(<VarExplanation>) = { INT }
	 * FIRST(<StmtSeq>) = { IF, DO, ID, RETURN, SCANF, PRINTF , '{' , ';' }
	 * FOLLOW(<ConstExplanation>) = {  }
	 * FOLLOW(<VarExplanation>) = {  }
	 * FOLLOW(<StmtSeq>) = {  }
	 * 
	 * FIRST(<ComStmt>) = { '{' }
	 * FOLLOW(<ComStmt>) > { VOID  , ‘-1’ }
	 * 
	 * @throws IOException
	 * 
	 **/
	private void ComStmt() throws IOException{
		match('{');
		
		if(curToken.tag == Tag.CONST)
			ConstExplanation();
		
		if(curToken.tag == Tag.INT)
			VarExplanation(null);
		
		StmtSeq();
		match('}');
		
		
		return;
	}
	
	/**
	 * <StmtSeq>  ::=  <Stmt> { <Stmt> }
	 * 
	 * FIRST(<Stmt>) = FIRST(<Stmt>) = { IF, DO, ID, RETURN, SCANF, PRINTF , '{' , ';' }
	 * 
	 * FIRST(<StmtSeq>) = FIRST(<Stmt>)
	 * 					= { IF, DO, ID, RETURN, SCANF, PRINTF , '{' , ';' }
	 * FOLLOW(<StmtSeq>) = { '}' }
	 * 
	 * @throws IOException
	 */
	
	private void StmtSeq() throws IOException{
		Stmt();						
		//	如果读入的词法单元不再<Stmt>的FOLLOW集合中，则继续 Stmt();
		while(curToken.tag != '}')
		{
			Stmt();
		}
		
		return;
	}
	
	/**
	 * <Stmt>  ::=    <ConditionStmt> 
	 * 				| <LoopStmt> 
	 * 				| ‘{’ <StmtSeq> ‘}’ 
	 * 				| <CallStmt> ; 
	 * 				| <AssignStmt> ; 
	 * 				| <ReturnStmt> ; 
	 * 				| <ReadStmt> ; 
	 * 				| <WriteStmt> ; 
	 * 				| ;
	 * 
	 * FIRST(<ConditionStmt>) = { IF }
	 * FIRST(<LoopStmt>) = { DO }
	 * FIRST(<CallStmt>) = { ID }			*****  Next = { '(' }
	 * FIRST(<AssignStmt>) = { ID }			*****  Next = { '=' }
	 * FIRST(<ReturnStmt>) = { RETURN }
	 * FIRST(<ReadStmt>) = { SCANF }
	 * FIRST(<WriteStmt>) = { PRINTF }
	 * 
	 * FIRST(<Stmt>) = { IF, DO, ID, RETURN, SCANF, PRINTF , '{' , ';' }
	 * FOLLOW(<Stmt>) = { ‘}’ , ';' , WHILE, IF, DO, ID, RETURN, SCANF, PRINTF , '{' }
	 * 
	 * @throws IOException
	 */
	private void Stmt() throws IOException{
		String idstr = new String("");
		
		switch(curToken.tag){
		case ';':			match(';'); return;
		
		case Tag.IF:		ConditionStmt(); return;
		
		case Tag.DO:		LoopStmt(); return;
		
		case '{':			match('{');
							StmtSeq();
							match('}');
							return;
						
		case Tag.RETURN:	ReturnStmt(); break;
		
		case Tag.SCANF:		ReadStmt(); break;
		
		case Tag.PRINTF:	WriteStmt(); break;
										
		case Tag.ID:		idstr = curToken.toString();
							match(Tag.ID);			// <AssignStmt> 与 <CallStmt> 在此发生冲突
							if(curToken.tag == '(')
							{ 	if(checkId(idstr)!=3){		//  不是已经定义的函数名
									System.out.println(idstr+"    : ");
									new Perror(Errors.SynUndefinedFunc).printErrorInfo(lexer.getLineno(), lexer.getWordno());
									skipTo(';');
									//System.exit(-1);
									break;
								}
								CallStmt(idstr);
								match(';');
															//  说明这是一个调用语句
															//	此时如果函数有返回值，将在运算栈保存有垃圾信息
															//  所以必须生成Pcode控制运算栈的栈的栈顶指针减1;
								FuncTable func = null;
								func = symboltable.getFunc(idstr);
								if(func.retType == FuncTable.INT){
									codestack.genINT(1);
								}
								return; 
							}
							if(curToken.tag == '=')
							{ 
								if(checkId(idstr)==0 || checkId(idstr)==3){		//  不是已经定义的变量名
									System.out.println(idstr+"    : ");
									new Perror(Errors.SynUndefinedId).printErrorInfo(lexer.getLineno(), lexer.getWordno());
									//System.exit(-1);
									skipTo(';');
									break;
								}
								if(getSym(idstr).type!=Symbol.VAR)
								{
									System.out.println(idstr+"    : ");
									new Perror(Errors.SynConstAssign).printErrorInfo(lexer.getLineno(), lexer.getWordno());
									//System.exit(-1);
									skipTo(';');
									break;
								}
								AssignStmt(idstr);
								break; 
							}
													//  出错！！！！  正常不可能执行到这里
		default:	
					System.out.println("Error Occured When Analyzing <Stmt>, We resume and reanalyze <Stmt>");
					new Perror(Errors.GraNonePreStmt).printErrorInfo(lexer.getLineno(), lexer.getWordno());
					skipStmt();
					//System.exit(-1);
					return;
		}
		
		match(';');
		return;
	}
	
	/**
	 * <ConditionStmt>  ::=  if  ‘(’ <Condition> ‘)’ <Stmt>
	 * 
	 * FIRST(<ConditionStmt>) = { IF }
	 * FOLLOW(<ConditionStmt>) = { ‘}’ , ';' , WHILE }
	 * 
	 * @throws IOException
	 */
	private void ConditionStmt() throws IOException{
		int tracerAddr,curAddr;			//回填指令所处的地址，要回填的跳转地址
		
		match(Tag.IF);
		match('(');
		tracerAddr = Condition(-1);
		match(')');
		Stmt();
		
		curAddr = codestack.getTop();
		
		codestack.tracerAddr(tracerAddr, curAddr);
		
		return;
	}
	
	/**
	 * <Condition>  ::=   <Expression>  <RelationOp>  <Id> 
	 * 					| <Expression>
	 * FIRST(<RelationOp>) = { '<' , <= , '>' , >= , != , == }
	 * FIRST(<Expression>) = { '+' , '-' } ^ FIRST(Term)
	 * 					   = { ID , '(' , '+' , '-' , NUM }
	 * 
	 * FIRST(<Condition>)  = { ID , '(' , '+' , '-' , NUM }
	 * FOLLOW(<Condition>) = { '}' , ')' }
	 * 
	 * @throws IOException
	 * @return 返回需要回填跳转地址的JPC指令所处的地址
	 * 
	 * loopEnter == -1表示该条件使用循环测试
	 * 
	 * 循环与IF语句有所不同，循环条件为真的时候要跳转，而IF条件为真的时候要顺序执行
	 * 所以在保证JPC指令执行不变的情况下，则测试条件要取反条件
	 */
	private int Condition(int loopEnter) throws IOException{
		Expression();
		// 预测下一个词法单元是否为<RelationOp>的FIRST集合中的元素
		
		String idstr = new String("");
		Symbol sym;
		
		int curAddr, opKind;						//暂存当前的指令地址，并将其返回，使其他分程序对其进行地址返填
		
		switch(curToken.tag){
		case '<':
		case '>':
		case Tag.SMALLER_EQUAL:
		case Tag.LARGER_EQUAL:
		case Tag.EQUAL:
		case Tag.NOT_EQUAL:		opKind = curToken.tag;
								match(curToken.tag);
								idstr = curToken.toString();
								if(checkId(idstr)==0)
								{
									System.out.println(idstr+"    : ");
									new Perror(Errors.SynUndefined).printErrorInfo(lexer.getLineno(), lexer.getWordno());
									//System.exit(-1);
								}
								
								match(Tag.ID);
								
								sym = getSym(idstr);
								if(sym.type == Symbol.CONST)				//如果是常量，直接查找符号表，把值放到栈顶
									codestack.genLIT(sym.constValue);
								else{										//如果是变量，直接查找符号表，生成数据栈的相对地址
																			//把值放到栈顶
									codestack.genLOD(sym.level, sym.address);
								}
								if(loopEnter == -1){		//  表示是IF语句中的条件
									//	此时运算栈的栈顶一定是<id>对应的信息，次栈顶一定是<Expression>对应的值
									//但是JPC指令的跳转地址需要进行返填才能得到
									curAddr = codestack.getTop();
									codestack.genJPC(opKind, -1);		//跳转地址为-1表示还未经过回填
									return curAddr;
								}else{						//  表示是Loop语句的入口地址
									switch(opKind){
									case '<':				opKind = Tag.LARGER_EQUAL; break;
									case '>':				opKind = Tag.SMALLER_EQUAL; break;
									case Tag.SMALLER_EQUAL:	opKind = '>'; break;
									case Tag.LARGER_EQUAL:	opKind = '<'; break;
									case Tag.EQUAL:			opKind = Tag.NOT_EQUAL; break;
									case Tag.NOT_EQUAL:		opKind = Tag.EQUAL; break;
									default:			System.out.println("Loop生成JPC条件取反有误！！");
															break;
									}
									
									codestack.genJPC(opKind, loopEnter);
									return -1;
								}
		//case Tag.ID:
		//case '(':
		//case '+':
		//case '-':
		//case Tag.NUM:			Expression();
		//						return;
								
		case '}':							//  读到FOLLOW集合中的元素， 直接返回
		case ')':		if(loopEnter == -1){		//  表示是IF语句中的条件		
							//  表示<Condition>仅仅是一个表达式，这时人为地在栈顶添加常量0
							//并且置<RelationOp>为'>'
							codestack.genLIT(0);
							curAddr = codestack.getTop();
							codestack.genJPC('>', -1);		//跳转地址为-1表示还未经过回填
							return curAddr;
						}else{								//  表示是Loop语句的入口地址
							codestack.genLIT(0);			//  测试条件取反
							codestack.genJPC(Tag.SMALLER_EQUAL, loopEnter);
							return -1;
						}
		
		default:	System.out.println("Error Occured When Analyzing <Condition>语法分析程序终止！！！");
					new Perror(Errors.GraNoneExpSym).printErrorInfo(lexer.getLineno(), lexer.getWordno());
					System.exit(-1);
					return -1;
		}

	}
	
	/**
	 * <Expression>  ::=   [ + | - ] <Term> { <SumOp> <Term> }
	 * 
	 * FIRST(<Term>) = { ID , '(' , '+' , '-' , NUM }
	 * FIRST(<Factor>) = { ID , '(' , '+' , '-' , NUM }
	 * FISRT(<Number>) = { '+' , '-' , NUM }
	 * FIRST(<CallStmt>) = { ID }
	 * FIRST(<SumOp>)  = { '+' ,  '-'  }
	 * 
	 * FIRST(<Expression>) = { ID , '(' , '+' , '-' , NUM }
	 * FOLLOW(<Expression>) = { '<' , <= , '>' , >= , != , == , ')' , ',' , ‘;’ , '}' }
	 * 			在此处进一步区分整数前面的加减号到底是运算符还是正负号
	 * 
	 * @throws IOException
	 */
	private void Expression() throws IOException{
					//  匹配 '+' 或者 '-', 此处'+' '-'是运算符，将被match()吃掉
					//  Caution!!! 如果下一个不是正负号， 则判定整数为正,进一步的分析交给Term();
		int opkind;
		Boolean negtive = false;			// 是否取相反数
		if(curToken.tag == '+' || curToken.tag == '-'){
			if(curToken.tag == '-')
				negtive = true;
			match(curToken.tag);
		}
		
		Term();						// 测试词法单元是否为<SumOp>的FIRST集合中的元素
		
		if(negtive == true)			//  生成对<Term>整体值取相反数的代码
		{
			codestack.genLIT(-1);	//  把  -1 放到栈顶
			codestack.genOPR('*');	//  次栈顶乘以-1放到栈顶
		}
		
		while(curToken.tag == '+' || curToken.tag == '-')
		{	
			opkind = curToken.tag;
			match(curToken.tag);
			Term();
			codestack.genOPR(opkind);
		}
		
		
		
		return;
	}
	
	/**
	 * <Term>  ::=  <Factor> { <MulOp> <Factor> }
	 * 
	 * FIRST(<MulOp>)  = { '*' ,  '/'  }
	 * 
	 * FIRST(<Term>) = FIRST(Factor) = { ID , '(' , '+' , '-' , NUM }
	 * FOLLOW(<Term>) = { '+' , '-' , '<' , <= , '>' , >= , != , == , ')' , ',' , ‘;’ , '}' }
	 * 
	 * @throws IOException
	 */
	private void Term() throws IOException{
		Factor();
							// 测试词法单元是否为<MulOp>的FIRST集合中的元素
		int opkind;
		while(curToken.tag == '*' || curToken.tag == '/')
		{
			opkind = curToken.tag;
			match(curToken.tag);
			Factor();
			codestack.genOPR(opkind);
		}
		
		return;
	}
	
	/**
	 * <Factor>     ::= 	<Id>  
	 * 				  	|  ‘(’ <Expression> ‘)’  
	 * 					|  	<Number>  
	 * 					|  	<CallStmt>
	 *
	 * FISRT(<Number>) = { '+' , '-' , NUM }
	 * FIRST(<CallStmt>) = { ID }
	 * 
	 * FIRST(<Factor>) = { ID , '(' } ^ FIRST(Number) ^ FIRST(CallStmt)
	 * 				   = { ID , '(' , '+' , '-' , NUM }	 
	 * FOLLOW(<Factor>) = { '*' , '/' , '+' , '-' , '<' , <= , '>' , >= , != , == , ')' , ',' , ‘;’ , '}' , ')' }
	 * 
	 * 	!!!  注意<Factor>的<Id> 与 <CallStmt> 有交集 { ID } ，必须进一步分析  !!!
	 * 
	 * @throws IOException
	 */
	private void Factor() throws IOException{
		// 根据右侧表达式的FIRST集合，选择合适的等式
		
		String idstr = new String("");
		
		int value;		//  变量的层次差，如果是在函数中的则层次差为1，若为全局的则层次差为0
		Symbol sym;
		
		switch(curToken.tag){
		
		case '+':
		case '-':
		case Tag.NUM:	value=Number();
						codestack.genLIT(value);
						return;			//  如果是正负号或者数字则说明该因子是整数，value就是Number
												//方法的返回值。
		
		case '(':	match('('); 
					Expression();
					match(')');
					return;
		
		case Tag.ID: 				// <CallStmt> 与  <Id> 在此发生冲突
					idstr = curToken.toString();
					match(Tag.ID);
					
					if(curToken.tag == '(')
					{	
						if(checkId(idstr)!=3){		//  不是已经定义的函数名
							System.out.println(idstr+"    : ");
							new Perror(Errors.SynUndefinedFunc).printErrorInfo(lexer.getLineno(), lexer.getWordno());
							//System.exit(-1);
							skipCallStmt();
							match(curToken.tag);
							skipFactor();
							return;
						}
						//  *****************************判断函数是否有返回值，如果没有不允许出现在exp中
						else if(getFunc(idstr).retType != FuncTable.INT)
						{
							System.out.println(idstr+"    : ");
							new Perror(Errors.SynNoneRetInExp).printErrorInfo(lexer.getLineno(), lexer.getWordno());
							//System.exit(-1);
							skipCallStmt();
							match(curToken.tag);
							skipFactor();
							return;
						}
						CallStmt(idstr); 
						return;
					}
					
					if(checkId(idstr)==0)
					{
						System.out.println(idstr+"    : ");
						new Perror(Errors.SynUndefined).printErrorInfo(lexer.getLineno(), lexer.getWordno());
						//System.exit(-1);
						skipFactor();
						return;
					}
									//  表明是合法<Id>
					sym = getSym(idstr);
					if(sym.type == Symbol.CONST)				//如果是常量，直接查找符号表，把值放到栈顶
						codestack.genLIT(sym.constValue);
					else{										//如果是变量，直接查找符号表，生成数据栈的相对地址
																//把值放到栈顶
						codestack.genLOD(sym.level, sym.address);
					}
					
					return;
		
		
		default :	System.out.println("Error Occured When Analyzing <Factor>, we resume and continue Analyzing！");
					new Perror(Errors.GraNonePreFactor).printErrorInfo(lexer.getLineno(), lexer.getWordno());
					skipFactor();
					//System.exit(-1);
					return;
		}

	}
	
	/**
	 * <LoopStmt>  ::=  do  <Stmt>  while  ‘(’ <Condition> ‘)’
	 * 
	 * FIRST(<LoopStmt>) = { DO }
	 * FOLLOW(<LoopStmt>) = { ‘}’ , ';' , WHILE }
	 * 
	 * @throws IOException
	 */
	private void LoopStmt() throws IOException{
		
		int loopEnter;
		
		match(Tag.DO);
		
		loopEnter = codestack.getTop();
		
		Stmt();
		match(Tag.WHILE);
		match('(');
		if(Condition(loopEnter)!=-1)
			System.out.println("循环语句入口地址填写有误！！！");
		match(')');
		
		return;
	}
	
	/**
	 * <CallStmt>   ::=  <Id> '(' <VarArgTable> ')'
	 * 
	 * FIRST(<CallStmt>) = { ID }
	 * FOLLOW(<CallStmt>) = { '*' , '/' , '+' , '-' , '<' , <= , '>' , >= , != , == , ')' , ',' , ‘;’ , '}' , ')' }
	 * 
	 * @throws IOException
	 */
	private void CallStmt(String funcname) throws IOException{
		
		// 由于<CallStmt> 只在 <Factor> 和  <Stmt> 中出现
		// 看Factor()和Stmt()过程知道 <Id> 已经被提前消耗
		// 所以直接从'('开始匹配！！！
		
						//  基本参数传递的思想：  把所有函数调用时需要的参数依次压到datastack的栈顶
						//在解释执行CAL指令的时候需要把参数依次保存到合适的变量地址中去。
		FuncTable func = null;
		func = symboltable.getFunc(funcname);
		// 查找函数信息表，将来需要从其中得到函数的入口地址
		int argnum1 = func.argTable.size();
		int argnum2;
		
		match('(');
		argnum2 = VarArgTable();
		match(')');
		
		if(argnum1 == argnum2)
			codestack.genCAL(func.addr);
		else{
			System.out.println("函数 "+func.funcname+"  : ");
			new Perror(Errors.SynCallArgsError).printErrorInfo(lexer.getLineno(), lexer.getWordno());
			//System.exit(-1);
		}
		
		
		return;
	}
	
	/**
	 * <VarArgTable>    ::=   <Expression> { , <Expression> } 
	 * 						| <Blank>
	 *
	 * FIRST(<Expression>) = { ID , '(' , '+' , '-' , NUM }
	 * 
	 * FIRST(<VarArgTable>) = FIRST(<Expression>) ^ { E }
	 * 						= { ID , '(' , '+' , '-' , NUM , E }
	 * FOLLOW(<VarArgTable>) = { ')' }
	 * 
	 * @throws IOException
	 */
	private int VarArgTable() throws IOException{
		
		int argnum = 0;
		
		if(curToken.tag == ')')			// 如果读到FOLLOW集合中的元素， 直接返回 表明是  “空”
			return argnum;
		
		Expression();					//  表达式分程序的执行必定会将结果依次压到运算栈栈顶
										//所以已经完成了将函数参数依次压到栈顶的操作
		argnum++;
		
		while(curToken.tag == ','){		// <Expression>分支
			match(',');
			Expression();
			argnum++;
		}
		
		return argnum;
	}
	
	/**
	 * <AssignStmt>   ::=  <Id> = <Expression>
	 * 
	 * FIRST(<AssignStmt>) = { ID }
	 * FOLLOW(<AssignStmt>) = { ';' }
	 * 
	 * @throws IOException
	 */
	private void AssignStmt(String idstr) throws IOException{
		
		// 由于<AssignStmt> 只在 <Stmt> 中出现
		// 看Stmt()过程知道 <Id> 已经被提前消耗
		// 所以直接从'='开始匹配！！！
		Symbol sym;
		
		match('=');
		Expression();
		
		sym = getSym(idstr);
		codestack.genSTO(sym.level, sym.address);
		
		return;
	}
	
	/**
	 * <ReturnStmt>   ::=  return  [ ‘(’ <Expression> ‘)’ ]
	 * 
	 * FIRST(<ReturnStmt>) = { RETURN }
	 * FOLLOW(<ReturnStmt>) = { ';' }
	 * 
	 * @throws IOException
	 */
	private void ReturnStmt() throws IOException{
		match(Tag.RETURN);
		
		if(curToken.tag == ';'){
			curFuncTable.hasRet = 1;
			codestack.genRET(0);						//	添加函数的返回指令，0表示子函数返回
			return;
		}
		
		match('(');
		Expression();
		match(')');
		
		curFuncTable.hasRet = 2;
		codestack.genRET(0);						//	添加函数的返回指令，0表示子函数返回
		return;
	}
	
	/**
	 * <ReadStmt>    ::=  scanf ‘(’ <Id> ‘)’
	 * 
	 * FIRST(<ReadStmt>) = { SCANF }
	 * FOLLOW(<ReadStmt>) = { ';' }
	 * 
	 * @throws IOException
	 */
	private void ReadStmt() throws IOException{
		
		String idstr = new String("");
		Symbol sym;
		int checkid,addr;		//  1 2表示函数中的变量 ， 4表示全局变量    0 3非法
		
		match(Tag.SCANF);
		match('(');
		
		idstr = curToken.toString();
		checkid = checkId(idstr);
		sym = (Symbol) getSym(idstr);
		
		match(Tag.ID);
		
		if(checkid==0 || checkid==3){		//  不是已经定义的变量名
			System.out.println(idstr+"    : ");
			new Perror(Errors.SynUndefinedId).printErrorInfo(lexer.getLineno(), lexer.getWordno());
			//System.exit(-1);
			skipTo(')');
			match(')');
			return;
		}
		if(sym.type!=Symbol.VAR)
		{
			System.out.println(idstr+"    : ");
			new Perror(Errors.SynConstAssign).printErrorInfo(lexer.getLineno(), lexer.getWordno());
			//System.exit(-1);
			skipTo(')');
			match(')');
			return;
		}
		
		
		match(')');
		
		addr = sym.address;
		if(checkid==4)			//表示全局变量
		{
			codestack.genRED(1, addr);
		}else{					//表示函数内的变量
			codestack.genRED(0, addr);
		}
		
		return;
	}
	
	/**
	 * <WriteStmt>   ::=   printf  ‘(‘ <Strings> , <Expression> ‘)’  
	 * 					|  printf  ‘(’ <Expression> ‘)’  
	 * 					|  printf  '(' <Strings> ')'
	 * 			注意<WriteStmt>文法右侧有很多公共部分，分析时可以提取一并分析
	 * 
	 * FIRST(<WriteStmt>) = { PRINTF }
	 * FOLLOW(<WriteStmt>) = { ';' }
	 * 
	 * 		
	 * @throws IOException
	 */
	private void WriteStmt() throws IOException{
		
		int offset;
		String str = new String("");
		
		match(Tag.PRINTF);
		match('(');
		
		if(curToken.tag == Tag.Strings){
			
			str = curToken.toString();
			match(Tag.Strings);
			offset = strstack.getTop();
			strstack.push(str);
			codestack.genWRT(1, offset);
			
			if(curToken.tag == ',')
			{
				match(',');
				Expression();
				codestack.genWRT(0, -1);
			}
		}else{
			Expression();
			codestack.genWRT(0, -1);
		}
		
		match(')');
		
		return;
	}
	/**
	 * 		跳读到指定的结束符号标记
	 * @param endTag
	 */
	public void skipTo(int endTag) throws IOException{
		while(curToken.tag != endTag && curToken.tag!=-1){
			match(curToken.tag);
		}
		return;
	}
	
	/**
	 * 		跳跃到<Stmt>的FOLLOW集合中的元素为止
	 * FOLLOW(<Stmt>) = { ‘}’ , ';' , WHILE, IF, DO, ID, RETURN, SCANF, PRINTF , '{' }
	 * @param endTag
	 * @throws IOException
	 */
	public void skipStmt() throws IOException{
		int t;
		while(true){
			t = curToken.tag;
			if(t=='}' || t==';' || t==Tag.WHILE || t==Tag.IF || t==Tag.DO || t==Tag.ID 
					|| t==Tag.RETURN || t== Tag.SCANF || t==Tag.PRINTF || t=='{' || t==-1)
				return;
			match(curToken.tag);
		}
	}
	
	/**
	 * 		跳跃到<Factor>的FOLLOW集合中的元素为止
	 * FOLLOW(<Factor>) = { '*' , '/' , '+' , '-' , '<' , <= , '>' , >= , != , == , ')' , ',' , ‘;’ , '}' }
	 * @param endTag
	 * @throws IOException
	 */
	public void skipFactor() throws IOException{
		int t;
		while(true){
			t = curToken.tag;
			if(t=='*' || t=='/' || t=='+' || t=='-' || t=='<' || t==Tag.SMALLER_EQUAL || t=='>' 
					|| t==Tag.LARGER_EQUAL || t== Tag.NOT_EQUAL || t==Tag.EQUAL || t==')' || t==','
						|| t== ';' || t=='}' || t==-1)
				return;
			match(curToken.tag);
		}
	}
	
	/**
	 * 		跳跃到<CallStmt>的FOLLOW集合中的元素为止
	 * FOLLOW(<CallStmt>) = { '*' , '/' , '+' , '-' , '<' , <= , '>' , >= , != , == , ')' , ',' , ‘;’ , '}'}
	 * @param endTag
	 * @throws IOException
	 */
	public void skipCallStmt() throws IOException{
		int t;
		while(true){
			t = curToken.tag;
			if(t=='*' || t=='/' || t=='+' || t=='-' || t=='<' || t==Tag.SMALLER_EQUAL || t=='>' 
					|| t==Tag.LARGER_EQUAL || t== Tag.NOT_EQUAL || t==Tag.EQUAL || t==')' || t==','
						|| t== ';' || t=='}' || t==-1)
				return;
			match(curToken.tag);
		}
	}
	
	/**
	 * 		跳跃到<ConstDefine>的FOLLOW集合中的元素为止
	 * FOLLOW(<ConstDefine>) = { ',' , ';' }
	 * @param endTag
	 * @throws IOException
	 */
	public void skipConstDefine() throws IOException{
		int t;
		while(true){
			t = curToken.tag;
			if(t==',' || t==';' || t==-1)
				return;
			match(curToken.tag);
		}
	}
	/**
	 * 		跳到VOID或者INT
	 * @throws IOException
	 */
	public void skipToVoidInt() throws IOException{
		int t;
		while(true){
			t = curToken.tag;
			if(t==Tag.VOID || t==Tag.INT || t==-1)
				return;
			match(curToken.tag);
		}
	}
	
	/**
	 * 		跳跃到<VarExplanation>的FOLLOW集合中的元素为止
	 * FOLLOW(<VarExplanation>) = { INT , VOID , IF, DO, ID, RETURN, SCANF, PRINTF , '{' , ';' }
	 * @throws IOException
	 */
	public void skipVarExplanation() throws IOException{
		int t;
		while(true){
			t = curToken.tag;
			if(t==Tag.VOID || t==Tag.INT || t==Tag.IF || t==Tag.DO || t==Tag.ID
					|| t== Tag.RETURN || t==Tag.SCANF || t== Tag.PRINTF ||
					t== '{' || t==';' || t==-1)
				return;
			match(curToken.tag);
		}
	}
}